package main

/*
robotSim 不使用哈希表 372ms 击败 6.25%使用 Go 的用户
robotSim2 使用哈希表 48ms 击败 78.13%使用 Go 的用户
*/
import (
	"fmt"
	//"math"
)

const (
	UP = iota
	LEFT
	DOWN
	RIGHT
)

type Robot struct {
	Direction int
	X         int
	Y         int
}

func (r *Robot) TurnLeft() {
	r.Direction++
	if r.Direction > RIGHT {
		r.Direction = UP
	}
}

func (r *Robot) TurnRight() {
	r.Direction--
	if r.Direction < UP {
		r.Direction = RIGHT
	}
}

/*
func (r *Robot) Run(length int, obstacles [][]int) {
	targetX, targetY := r.X, r.Y

	blocked := false
	switch r.Direction {
	case UP:
		minY := math.MaxInt32
		for _, obstacle := range obstacles {
			if obstacle[0] == r.X && r.Y < obstacle[1] && obstacle[1] <= r.Y+length {
				minY = Min(minY, obstacle[1]-1)
				blocked = true
			}
		}
		targetX = r.X
		if blocked {
			targetY = minY
		} else {
			targetY = r.Y + length
		}
	case DOWN:
		maxY := math.MinInt32
		for _, obstacle := range obstacles {
			if obstacle[0] == r.X && r.Y-length <= obstacle[1] && obstacle[1] < r.Y {
				maxY = Max(maxY, obstacle[1]+1)
				blocked = true
			}
		}
		targetX = r.X
		if blocked {
			targetY = maxY
		} else {
			targetY = r.Y - length
		}
	case LEFT:
		maxX := math.MinInt32
		for _, obstacle := range obstacles {
			if obstacle[1] == r.Y && r.X-length <= obstacle[0] && obstacle[0] < r.X {
				maxX = Max(maxX, obstacle[0]+1)
				blocked = true
			}
		}
		targetY = r.Y
		if blocked {
			targetX = maxX
		} else {
			targetX = r.X - length
		}
	case RIGHT:
		minX := math.MaxInt32
		for _, obstacle := range obstacles {
			if obstacle[1] == r.Y && r.X < obstacle[0] && obstacle[0] <= r.X+length {
				minX = Min(minX, obstacle[0]-1)
				blocked = true
			}
		}
		targetY = r.Y
		if blocked {
			targetX = minX
		} else {
			targetX = r.X + length
		}
	}
	r.X = targetX
	r.Y = targetY
}
*/

func (r *Robot) GetDistanceToZero() int {
	return r.X*r.X + r.Y*r.Y
}

func (r *Robot) RunOneStep(obstacleSet map[[2]int]bool) {
	x, y := r.X, r.Y
	switch r.Direction {
	case UP:
		x, y = r.X, r.Y+1
	case DOWN:
		x, y = r.X, r.Y-1
	case LEFT:
		x, y = r.X-1, r.Y
	case RIGHT:
		x, y = r.X+1, r.Y
	}
	p := [2]int{x, y}
	if contains := obstacleSet[p]; !contains {
		r.X, r.Y = x, y
	}
}

/*
func Min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func Max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func robotSim(commands []int, obstacles [][]int) int {
	robot := &Robot{
		Direction: UP,
		X:         0,
		Y:         0,
	}
	res := 0
	for _, cmd := range commands {
		switch cmd {
		case -2:
			robot.TurnLeft()
		case -1:
			robot.TurnRight()
		default:
			robot.Run(cmd, obstacles)
			distance := robot.GetDistanceToZero()
			if distance > res {
				res = distance
			}
		}
	}
	return res
}
*/

func robotSim2(commands []int, obstacles [][]int) int {
	obstacleSet := make(map[[2]int]bool)
	for _, obs := range obstacles {
		obstacleSet[[2]int{obs[0], obs[1]}] = true
	}

	robot := &Robot{
		Direction: UP,
		X:         0,
		Y:         0,
	}
	res := 0
	for _, cmd := range commands {
		switch cmd {
		case -2:
			robot.TurnLeft()
		case -1:
			robot.TurnRight()
		default:
			for i := 0; i < cmd; i++ {
				robot.RunOneStep(obstacleSet)
			}
			distance := robot.GetDistanceToZero()
			if distance > res {
				res = distance
			}
		}
	}
	return res
}

func main() {
	commands := make([]int, 0)
	obstacles := make([][]int, 0)
	commands = append(commands, 4, -1, 3)

	fmt.Println(robotSim2(commands, obstacles))
}
